﻿//=======================================================
// 作者：LR
// 公司：广州纷享科技发展有限公司
// 描述：
// 创建时间：2021-06-23 16:40:27
//=======================================================
using fs;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Sailfish;

public static partial class Extend
{
    public static TimeExtend UpdateCall<T>(this T target)
    {
        int id = target.GetHashCode();
        TimeExtend timeClass = ClassPool.Get<TimeExtend>();
        TimeMgr.AddTimer(id, timeClass);

        timeClass.Init(target.GetHashCode(), 0.001f);
        return timeClass;
    }

    public static TimeExtend UpdateUnilt<T>(this T target)
    {
        int code = target.GetHashCode();
        TimeExtend timeClass = ClassPool.Get<TimeExtend>();
        timeClass.Init(target.GetHashCode(), int.MaxValue);
        TimeMgr.AddTimer(code, timeClass);
        return timeClass;
    }

    public static TimeExtend UpdateUntil<T>(this T target, float delay)
    {
        int code = target.GetHashCode();
        TimeExtend timeClass = ClassPool.Get<TimeExtend>();
        TimeMgr.AddTimer(code, timeClass);

        timeClass.Init(target.GetHashCode(), delay);
        return timeClass;
    }


    public static TimeExtend UpdateTime<T>(this T target, float delay, CallType callUpdate = CallType.Update)
    {
        int code = target.GetHashCode();
        TimeExtend timeClass = ClassPool.Get<TimeExtend>();
        TimeMgr.AddTimer(code, timeClass);

        timeClass.Init(target.GetHashCode(), delay, callUpdate);
        return timeClass;
    }

    public static IDisposable TimeCall(this ITimer timer, System.Action action)
    {
        var temp = new TimeCall(action) { timeCode = timer.timeCode };
        timer.next = temp;
        return temp;
    }

    public static ITimer TimeOnComplete(this ITimer timer, System.Action action)
    {
        var temp = new TimeOnComplete(action) { timeCode = timer.timeCode };
        timer.next = temp;
        temp.timeCode = timer.timeCode;
        return temp;
    }

    public static ITimer TimeOnComplete(this ITimer timer)
    {
        var temp = new TimeOnComplete() { timeCode = timer.timeCode };
        timer.next = temp;
        temp.timeCode = timer.timeCode;
        return temp;
    }

    public static ITimer TimeOnInterval(this TimeExtend timer, float interval)
    {
        var temp      = new TimeOnInterval(interval, null);
        timer.next    = temp;
        temp.timeCode = timer.HashCode;
        return temp;
    }

    public static ITimer TimeOnInterval(this TimeExtend timer,float interval, System.Action<float> action)
    {
        var  temp          = new TimeOnInterval(interval, action);
             timer.next    = temp;
             temp.timeCode = timer.HashCode;
        return temp;
    }

    public static ITimer TimeOnInterval(this ITimer timer, float interval, System.Action<float> action)
    {
        var temp           = new TimeOnInterval(interval, action);
            timer.next     = temp;
            temp.timeCode  = timer.timeCode;
        return timer;
    }


    public static ITimer TimeOnProcess<T>(this TimeExtend timer, System.Func<float, bool> action)
    {
        var temp       = new TimeOnProcess(timer.DelayTime, action);
        timer.next     = temp;
        temp .timeCode = timer.HashCode;
        return temp;
    }
    
    public static ITimer TimeOnProcess<T>(this ITimer timer, System.Func<float, bool> action)
    {
        var temp      = new TimeOnProcess(timer.runtime, action);
        timer.next    = temp;
        temp.timeCode = timer.timeCode;
        return temp;
    }



    public static ITimer TimeOnUnity(this TimeExtend timer, System.Func<float ,bool> func)
    {
        var temp      = new TimeOnUnity(timer.DelayTime, func);
        temp.timeCode = timer.HashCode;
        timer.next    = temp;
        return temp;
    }
    public static ITimer TimeOnUnity(this ITimer timer, System.Func<float, bool> func)
    {
        var temp = new TimeOnUnity(timer.runtime, func);
        timer.next = temp;
        temp.timeCode = timer.timeCode;
        return temp;
    }


    public static ITimer TimeOnWhile(this TimeExtend timer, System.Func<float, bool> func)
    {
        var temp = new TimeOnUnity(timer.DelayTime, func);
        temp.timeCode = timer.HashCode;
        timer.next = temp;
        return temp;
    }

    public static ITimer TimeOnWhile(this ITimer timer, System.Func<float, bool> func)
    {
        var temp = new TimeOnUnity(timer.runtime, func);
        temp.timeCode = timer.timeCode;
        timer.next = temp;
        return temp;
    }


    public static void StopThisOfTime<T>(this T target)
    {
        TimeMgr.Stop(target.GetHashCode());
    }

    public static void Stop(this TimeExtend target)
    {
        target.Recycle();
    }
}



public struct TimeCode
{
    public int typeCode;
    public int extendCode;

    public override int GetHashCode()
    {
        return extendCode;
    }
}


public class TimeMgr
{

    public static Dictionary<TimeCode, TimeExtend> timerValues = new Dictionary<TimeCode, TimeExtend>();
    public static List<TimeCode> codes = new List<TimeCode>();

    public static void AddTimer(int typeID, TimeExtend extend)
    {
        var code     = extend.GetHashCode();
        var timeCode = new TimeCode() { typeCode = typeID, extendCode = code };
        codes.Add(timeCode);
    }



    public static void ClearTimer(TimeCode timecode)
    {
        if(codes.Contains(timecode))
        {
            codes.Remove(timecode);
        }
    }

    public static void Stop(TimeCode timecode)
    {
        if (codes.Contains(timecode))
        {
            codes.Remove(timecode);
            timerValues[timecode].Recycle();
            timerValues.Remove(timecode);
        }
    }


    public static void Stop(int typeCode)
    {
        var finds = codes.FindAll(_ => _.extendCode == typeCode);

        if (finds.Count > 0)
        {
            finds.ForEach(_ => 
            {
                timerValues[_].Recycle();
                timerValues   .Remove(_);
            });
        }
    }


    public static float Ceil(float value)
    {
       return  Mathf.CeilToInt(value * 1000.0f)/1000.0f;
    }
}


/// <summary>
/// 时间延迟类
/// </summary>
public class TimeExtend : CustomYieldInstruction, INotifyCompletion
{
    private System.Action actionAwaiter;
    public ITimer next = null;

    float    m_playTime;
    float    m_delayTime;
    CallType m_callType;
    bool isCompleted = false;

    public float DelayTime  => m_delayTime;
    public TimeCode HashCode;
    public void Init(int code, float delay, CallType type = CallType.Update)
    {
        m_playTime    = 0;
        m_delayTime   = delay;
        m_callType    = type;
        isCompleted   = false;
  
      
        if (type == CallType.Update
         || type == CallType.LateUpdate
         || type == CallType.FixedUpdate)
        {
            CallUnit.destroyCall.AddListener(Recycle);
        }
        CallUnit.GetCallEvent(m_callType).AddListener(Update);
    }


    public void Update()
    {
        try
        {
            if (next != null)
            {
                if (next.Update(m_playTime) == false || isCompleted || m_playTime >= m_delayTime)
                {
                    this . Recycle();
                }
                m_playTime += Time.deltaTime;
            }
        }
        catch (System.Exception e)
        {
            Recycle();
            Debug.LogError($"Timer报错：{e.Message}————清空事件");
        }
    }


    public void Recycle()
    {
        Debug.Log("shifang");

        next      . Recycle();
        ClassPool . Release(this);
        TimeMgr   . ClearTimer(HashCode);
        CallUnit  . destroyCall.RemoveListener(Recycle);
        CallUnit  . GetCallEvent(m_callType).RemoveListener(Update);

        next        = null;
        isCompleted = true;
    }


    #region 协程回调
    public override bool keepWaiting
    { 
        get
        {
            return !isCompleted;
        }
    }
    #endregion


    #region 异步回调

    public bool IsCompleted => isCompleted;
    public TimeExtend GetAwaiter()
    {
        return this;
    }

    public void GetResult()
    {
        // 如果异步操作失败，则会在这里抛出异常
    }

    public void OnCompleted(Action continuation)
    {
        actionAwaiter = continuation;
    }
    #endregion

    #region 事件委托回调
    /// <summary>
    /// 时间延时完成后执行
    /// </summary>
    public TimeExtend OnFinish(System.Action action)
    {
  
        return this;
    }

    #endregion
}

public class TimeCall : IDisposable , ITimer
{
    public ITimer   next { get ; set; }
    public TimeCode timeCode { get ; set ; }
    public float    runtime { get; set; }

    public Action Action;

    public TimeCall(Action action)
    { 
      Action = action;
    }

    public void Dispose()
    {
        TimeMgr.Stop(timeCode);
    }

    public void Recycle()
    {
        next   ?.Recycle();
        next   = null;
        Action = null;
    }

    public bool Update(float time)
    {
        Action?.Invoke();
        return false;
    }
}
public class TimeOnComplete : IDisposable, ITimer
{
    public ITimer next { get; set; }
    public TimeCode timeCode { get; set; }
    public float runtime { get; set; }

    public Action Action;

    public TimeOnComplete(Action action)
    {
        Action = action;
    }

    public TimeOnComplete()
    {

    }

    public void Dispose()
    {
        TimeMgr.Stop(timeCode);
    }

    public void Recycle()
    {
        next?.Recycle();
        next   = null;
        Action = null;
    }

    public bool Update(float time)
    {
        Action?.Invoke();
        next?.Update(time);

        Debug.Log("only");
        Dispose();
        return true;
    }
}

public interface ITimer
{
    ITimer    next         { get; set;}
    TimeCode  timeCode     { get; set; }
    float     runtime      { get; set; }
    void      Recycle();
    bool      Update(float time);
}



public class TimeOnDelay : ITimer
{ 
    public float       time;
    bool   isCompleted = false;

    public TimeOnDelay(float time)
    {
        this.time   = time;
        isCompleted = true;
    }
    public ITimer   next     { get; set; }
    public float    runtime  { get; set; }
    public TimeCode timeCode { get; set; }

    public void Recycle()
    {
        next ?. Recycle();
        next  = null;
    }

    public bool Update(float time)
    {
        if (time >= this.time)
        {
            isCompleted = false;
            next?.Update(time);
            Recycle();
        }
        return isCompleted;
    }
}

public class TimeOnProcess : ITimer
{
    public float            time;
    public Func<float,bool> func;
    public Action<float>    action;
    public ITimer   next     { get; set; }
    public TimeCode timeCode { get; set; }
    public float    runtime  { get; set; }

    bool isCompleted = false;

    public void Recycle()
    {
        next?.Recycle();
        isCompleted = false;
        func        = null;
        action      = null;
        next        = null;
    }

    public TimeOnProcess(float time)
    {
        this.time = time;
        isCompleted = true;
    }

    public TimeOnProcess(float time, Action<float> action)
    {
        this.time   = time;
        this.action = action;
        isCompleted = true;
    }
    public TimeOnProcess(float time, Func<float, bool> func)
    {
        this.time   = time;
        this.func   = func;
        isCompleted = true;
    }

    public bool Update(float time)
    {
        if (action == null)
        {
            return isCompleted;
        }

        var value = Mathf.InverseLerp(0, this.time, time);

        if (func != null)
        {
            if (func.Invoke(time))
            {
                next.Update(value);
            }
        }
        else
        {
            action?.Invoke(value);
            next.Update(value);
        }

        return isCompleted;
    }
}

public class TimeOnInterval : ITimer
{
    public float time;
    public Action<float> action;
    public ITimer   next     { get; set; }
    public TimeCode timeCode { get; set; }
    public float    runtime  { get; set; }

    bool isPlay = false;
    public void Recycle()
    {
        next?.Recycle();
        isPlay = false;
        action = null;
        next   = null;
    }

    float playTime = 0;

    public TimeOnInterval(float time)
    {
        this.time = time;
    }

    public TimeOnInterval(float time, Action<float> action)
    {
        this.time   = time;
        this.action = action;
    }

    public bool Update(float time)
    {
    
        if (isPlay == false)
        {
            isPlay = true;
            playTime = time;
        }


        if (TimeMgr. Ceil(time - playTime) >= this.time)
        {
            playTime = time;
            action?.Invoke(time);
            next.Update(time);
        }

        return true;
    }
}

public class TimeOnUnity : ITimer
{
    public float time;
    public Func<float, bool> action;
    public ITimer next { get; set; }
    public TimeCode timeCode { get; set; }
    public float runtime { get; set; }

    public void Recycle()
    {
        next?.Recycle();
        action = null;
        next = null;
    }

    public TimeOnUnity(float time, System.Func<float, bool> action)
    {
        this.time   = time;
        this.action = action;
    }

    public bool Update(float time)
    {
        if (action == null)
        {
            return false;
        }

        if (action.Invoke(time))
        { 
            next . Update(time);
        }

        return true;
    }
}

public class TimeOnWhile : ITimer
{
    public float time;
    public Func<float, bool> func;

    public ITimer next { get; set; }
    public TimeCode timeCode { get; set; }
    public float runtime { get; set; }
    public void Recycle()
    {
        next?.Recycle();
        func = null;
        next = null;
    }

    public TimeOnWhile(float time, System.Func<float, bool> action)
    {
        this.time = time;
        this.func = action;
    }

    public bool Update(float time)
    {
        if (func == null)
        {
            return false;
        }

        if (func.Invoke(time) == false)
        {
            next.Update(time);
        }

        return true;
    }
}

public class Time2Task : INotifyCompletion
{
    bool isCompleted = false;
    public bool IsCompleted => isCompleted;
    private Action actionAwaiter;
    public Time2Task GetAwaiter()
    {
        return this;
    }

    public void GetResult()
    {
        // 如果异步操作失败，则会在这里抛出异常
    }

    public void OnCompleted(Action continuation)
    {
        actionAwaiter = continuation;
    }
}